<template>
  <div :class="getClass">
    <img
        v-show="isReady"
        ref="imgElRef"
        :src="src"
        :crossorigin="crossorigin"
        :style="getImageStyle"
    />
  </div>
</template>

<script lang="ts" setup>
import { Nullable } from '@zm-pkg/core'
import { CSSProperties } from 'vue'
import Cropper from 'cropperjs'
import { useDebounceFn } from '@vueuse/shared'
import { basicProps, defaultOptions } from './props'

const props = defineProps({
  ...basicProps,
  src: {
    type: String,
    required: true
  }
})
const emits = defineEmits(['cropend', 'ready'])
const attrs = useAttrs()

const cropper = ref<Nullable<Cropper>>()
const imgElRef = ref<HTMLImageElement>()
const isReady = ref(false)

const debounceRealTimeCroppered = useDebounceFn(realTimeCroppered, 80)

const getClass = computed(() => {
  return [
    'dt-cropper-image',
    attrs.class,
    {
      [`dt-cropper-image--circled`]: props.circled,
    },
  ]
})

const getImageStyle = computed((): CSSProperties => {
  return {
    height: props.height,
    maxWidth: '100%',
    ...props.imageStyle,
  }
})


onMounted(init)


async function init() {
  const imgEl = unref(imgElRef)

  if (!imgEl) return

  cropper.value = new Cropper(imgEl, {
    ...defaultOptions,
    ready: () => {
      isReady.value = true

      realTimeCroppered()

      emits('ready', cropper.value)
    },
    zoom: debounceRealTimeCroppered,
    cropmove: debounceRealTimeCroppered,
    ...props.options
  })
}

function realTimeCroppered() {
  props.realTimePreview && croppered()
}

function croppered() {
  if (!cropper.value) return

  let imgInfo = cropper.value.getData()
  const canvas = props.circled ? getRoundedCanvas() : cropper.value.getCroppedCanvas()

  canvas.toBlob((blob) => {
    if (!blob) return

    let fileReader: FileReader = new FileReader()
    fileReader.readAsDataURL(blob)
    fileReader.onloadend = (e) => {
      emits('cropend', {
        imgBase64: e.target?.result ?? '',
        imgInfo,
      })
    }
  }, 'image/png')

}

// 获取圆形的画布
function getRoundedCanvas() {
  const sourceCanvas = cropper.value!.getCroppedCanvas()
  const canvas = document.createElement('canvas')
  const context = canvas.getContext('2d')!
  const width = sourceCanvas.width
  const height = sourceCanvas.height
  canvas.width = width
  canvas.height = height

  context.imageSmoothingEnabled = true
  context.drawImage(sourceCanvas, 0, 0, width, height)
  context.globalCompositeOperation = 'destination-in'
  context.beginPath()
  context.arc(width / 2, height / 2, Math.min(width, height) / 2, 0, 2 * Math.PI, true)
  context.fill()

  return canvas
}
</script>

<style lang="less">
.dt-cropper-image{
  height: 100%;
  &--circled{
    .cropper-view-box,
    .cropper-face {
      border-radius: 50%;
    }
  }
}
</style>